package edu.hawaii.myisern.model;

import java.io.File;
import java.io.FileWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import edu.hawaii.myisern.researchers.jaxb.Researcher;
import edu.hawaii.myisern.researchers.jaxb.Researchers;

/**
 * Implements a wrapper class to handle the Researcher data for the MyISERN system.
 * 
 * @author Andrew Wong
 *
 */
public class ResearcherData  implements DisplayableIsernData {

  /**
   * Retrieves the Researchers object stored within.  Used for semantic checking.
   * 
   * @return Instance of Researchers object.
   */
  Researchers getResearchers() {
    return this.researchers;
  }

  /**
   * Retrieves the data stored in the object.
   * 
   * @return A list of objects in String representation, 
   * entries corresponding to the header entries.
   */
  @Override
  public List<List<String>> getData() {
    List<List<String>> result = new ArrayList<List<String>>();
    
    for (Researcher item : this.researchers.getResearcher()) {
      List<String> entry = new ArrayList<String>();
      
      entry.add(MyIsernModel.nullToEmpty(item.getName()));
      entry.add(MyIsernModel.nullToEmpty(item.getOrganization()));
      entry.add(MyIsernModel.nullToEmpty(item.getEmail()));
      entry.add(MyIsernModel.nullToEmpty(item.getPictureLink()));
      entry.add(MyIsernModel.nullToEmpty(item.getBioStatement()));
      
      result.add(entry);
    }
   
    return result;
  }
  
  /**
   * Retrieves the field names for the data that is returned.
   * 
   * @return Field names in a list.
   */
  @Override
  public List<String> getHeader() {
    List<String> result = new ArrayList<String>();
    result.add("Name");
    result.add("Organization");
    result.add("Email");
    result.add("Picture Link");
    result.add("Bio-Statement");
    return result;
  }

  private JAXBContext researchersJaxbContext;
  private Researchers researchers;

  /**
   * Saves data to an XML file.
   * 
   * @param baseDir Directory to save files to.
   * @return true if successful.
   */
  public boolean saveData(String baseDir) {
    Marshaller marshaller;
    try {
      marshaller = this.researchersJaxbContext.createMarshaller();
      StringWriter writer = new StringWriter();
      marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT , Boolean.TRUE);
      marshaller.marshal(this.researchers, writer);
      
      FileWriter researcherFile = new FileWriter(baseDir + "researchers.xml");
      researcherFile.write(writer.toString());
      researcherFile.close();


      return true;
    }
    catch (Exception e) {
      e.printStackTrace();
      
      return false;
    }
  }
  
  /**
   * Loads data from XML file.  If baseDir does not exist, it creates
   * an empty data set.
   * 
   * @param baseDir Directory to load data from.
   * @return true if data is loaded successful, false if data load failed.
   */
  public boolean loadData(String baseDir) {
    try {
      // Now do it once more for the researchers. 
      this.researchersJaxbContext = JAXBContext.newInstance("edu.hawaii.myisern.researchers.jaxb");
      File researchersFile = new File(baseDir + "researchers.xml");
      Unmarshaller unmarshaller = this.researchersJaxbContext.createUnmarshaller();
      this.researchers = (Researchers) unmarshaller.unmarshal(researchersFile);
      
      return true;
    }
    catch (Exception e) {
      Researcher foo = new Researcher();
      foo.setName(e.toString());
      
      researchers = new Researchers();
      researchers.getResearcher().add(foo);
      
      foo = new Researcher();
      foo.setName(baseDir + "/researchers.xml");
      researchers.getResearcher().add(foo);
      
      return false;
    }
  }

  /**
   * Updates or creates the array containing the row that was edited or added.
   * @param newEntry contains the edited/added entry.
   * @param toAdd true if is a new added entry.
   * @return String containing error message, if any.
   */
  @Override
  public String updateData(List<String> newEntry, boolean toAdd) {
    // find the entry first
    Researcher target = null;
    
    for (Researcher item : this.researchers.getResearcher()) {
      if (newEntry.get(0).trim().equals(item.getName())) {
        target = item;
      }
    }
    
    if (target == null && toAdd) {
      target = new Researcher();
      this.researchers.getResearcher().add(target);
    }
    else if (target != null && toAdd) {
      return " Researcher " + newEntry.get(0) + " already exists.";
    }
    else if (target == null && !toAdd) {
      return " Researcher " + newEntry.get(0) + " does not exist, cannot edit.";
    }
    
    //    result.add("Name");
    target.setName(newEntry.get(0).trim());
    
    //    result.add("Organization");
    target.setOrganization(newEntry.get(1).trim());
        
    //    result.add("Email");
    target.setEmail(newEntry.get(2).trim());
    
    //    result.add("Picture Link");
    target.setPictureLink(newEntry.get(3).trim());
    
    //    result.add("Bio-Statement");
    target.setBioStatement(newEntry.get(4).trim());

    return "";
  }
  

}
